package com.glp.work.flow.controller;

import com.glp.common.reponse.BaseResult;
import com.glp.work.flow.client.WfProcessClient;
import com.glp.work.flow.constant.APICode;
import com.glp.work.flow.constant.Keys;
import com.glp.work.flow.constant.OrderOperation;
import com.glp.work.flow.exception.APIException;
import com.glp.work.flow.pojo.WfBatchOrder;
import com.glp.work.flow.request.OrderApprovalDTO;
import com.glp.work.flow.request.OrderBatchApprovalDTO;
import com.glp.work.flow.response.OrderBatchApprovalResponse;
import com.glp.work.flow.response.TaskExecutionInfoResponse;
import com.glp.work.flow.response.WfOrderResultDTO;
import com.glp.work.flow.service.*;
import com.glp.work.flow.utils.RedisManage;
import com.glp.work.flow.utils.TraceIDUtils;
import com.glp.work.flow.utils.YzmUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
import org.flowable.common.engine.api.FlowableTaskAlreadyClaimedException;
import org.flowable.engine.TaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;

/**
 * 流程管理Controller
 *
 * @author jhuang1
 */
@Api(tags = {"流程管理Controller"})
@Slf4j
@RequestMapping("/process")
@RestController
public class WfProcessController implements WfProcessClient {

    @Resource
    private WfProcessService wfProcessService;
    @Resource
    private WfFormService wfFormService;
    @Autowired
    private RedisManage redisManage;
    @Resource
    WfBatchService wfBatchService;
    @Autowired
    TaskService taskService;
    @Autowired
    UserService userService;
    @Resource
    private WfEmailLogService wfEmailLogService;

    /**
     * 工单审批接口
     */
    @ApiOperation(value = "工单审批接口带有领取任务")
    @PostMapping(value = "/orderApprovallCaimTask")
    @ResponseBody
    public BaseResult<TaskExecutionInfoResponse> orderApproval(@RequestHeader(value = Keys.USERNO) String userNo,
                                                               @RequestBody @Validated OrderApprovalDTO orderApprovalDTO) {
        orderApprovalDTO.setUserNo(userNo);
        return orderApproval(orderApprovalDTO);
    }

    @ApiOperation(value = "工单审批接口已经领取过任务")
    @PostMapping(value = "/orderApproval")
    @ResponseBody
    public BaseResult<TaskExecutionInfoResponse> orderApprovalNoclaim(@RequestHeader(value = Keys.USERNO) String userNo,
                                                                      @RequestBody @Validated OrderApprovalDTO orderApprovalDTO) {
        orderApprovalDTO.setUserNo(userNo);
        orderApprove(orderApprovalDTO);
        return getTaskExecutionInfoResponseBaseResult(orderApprovalDTO);
    }

    private BaseResult<TaskExecutionInfoResponse> getTaskExecutionInfoResponseBaseResult(@Validated @RequestBody OrderApprovalDTO orderApprovalDTO) {
        //判断是否在批量审批中
        WfBatchOrder batchOrder = wfBatchService.getWfBatchOrder(orderApprovalDTO.getTaskId());
        if (batchOrder != null) {
            throw new APIException(APICode.DATA_ERROR, "当前任务已经在批量审批中");
        }
        String executionId = wfProcessService.orderApproval(orderApprovalDTO);
        TaskExecutionInfoResponse response = new TaskExecutionInfoResponse();
        response.setExecutionId(executionId);
        BaseResult<TaskExecutionInfoResponse> baseResult = new BaseResult<>(APICode.SUCCESS.getCode(), "工单审批成功！" + TraceIDUtils.getLogTraceId(), response);
        log.info("工单审批接口,响应结果:{}", baseResult);
        return baseResult;
    }

    @ApiOperation(value = "工单审批接口Feign")
    @PostMapping(value = "/client/orderApproval")
    @ResponseBody
    @Override
    public BaseResult<TaskExecutionInfoResponse> orderApproval(@RequestBody OrderApprovalDTO orderApprovalDTO) {
        orderApprove(orderApprovalDTO);
        try {
            log.info("领取任务：{}", orderApprovalDTO);
            taskService.claim(orderApprovalDTO.getTaskId(), orderApprovalDTO.getUserNo());
        } catch (FlowableObjectNotFoundException e) {
            log.error("当前任务不存在！{}", orderApprovalDTO);
            throw new APIException(APICode.DATA_ERROR, "当前任务不存在！taskId：" + orderApprovalDTO.getTaskId());
        } catch (FlowableTaskAlreadyClaimedException e) {
            log.error("当前任务已被领取！：{}", orderApprovalDTO);
            throw new APIException(APICode.DATA_ERROR, "当前任务已被领取！taskId：" + orderApprovalDTO.getTaskId());
        }
        orderApprovalDTO.setUserNo(orderApprovalDTO.getUserNo());
        log.info("工单审批接口,请求参数:{}", orderApprovalDTO);
        BaseResult<TaskExecutionInfoResponse> taskExecutionInfoResponseBaseResult = orderApprovalNoclaim(orderApprovalDTO.getUserNo(), orderApprovalDTO);
        return taskExecutionInfoResponseBaseResult;
    }

    @ApiOperation(value = "工单审批接口Feign 2.0(没有领取任务的动作)")
    @PostMapping(value = "/client/orderApprovalTwo")
    @ResponseBody
    @Override
    public BaseResult<TaskExecutionInfoResponse> orderApprovalTwo(@RequestBody OrderApprovalDTO orderApprovalDTO) {
        orderApprove(orderApprovalDTO);
        orderApprovalDTO.setUserNo(orderApprovalDTO.getUserNo());
        log.info("工单审批接口,请求参数:{}", orderApprovalDTO);
        BaseResult<TaskExecutionInfoResponse> taskExecutionInfoResponseBaseResult = orderApprovalNoclaim(orderApprovalDTO.getUserNo(), orderApprovalDTO);
        return taskExecutionInfoResponseBaseResult;
    }

    private void orderApprove(@Validated @RequestBody OrderApprovalDTO orderApprovalDTO) {
        log.info("工单审批接口：req：{}", orderApprovalDTO);
        if (StringUtils.isBlank(orderApprovalDTO.getUserNo())) {
            throw new APIException(APICode.DATA_ERROR, "用户编码不能为空！");
        }
        if (OrderOperation.valueOf(orderApprovalDTO.getResult()) == null) {
            throw new APIException(APICode.DATA_ERROR, "不支持的审批操作！Operation=" + orderApprovalDTO.getResult());
        }
        if (StringUtils.isBlank(orderApprovalDTO.getTaskId())) {
            throw new APIException(APICode.DATA_ERROR, "任务Id不能为空");
        }
    }

    @Override
    @ApiOperation(value = "工单批量审批接口")
    @PostMapping(value = "/client/orderBatchApproval")
    @ResponseBody
    public BaseResult<OrderBatchApprovalResponse> orderBatchApproval(@RequestHeader String userNo, @RequestBody OrderBatchApprovalDTO orderBatchApprovalDTO) {
        log.info("工单批量审批接口：req：{}", orderBatchApprovalDTO);
        if (StringUtils.isBlank(userNo)) {
            throw new APIException(APICode.DATA_ERROR, "用户编码不能为空！");
        }
        if (OrderOperation.valueOf(orderBatchApprovalDTO.getResult()) == null) {
            throw new APIException(APICode.DATA_ERROR, "不支持的审批操作！Operation=" + orderBatchApprovalDTO.getResult());
        }
        orderBatchApprovalDTO.setUserNo(userNo);
        if (!CollectionUtils.isEmpty(orderBatchApprovalDTO.getWfOrderResultDTOS())) {
            List<WfOrderResultDTO> wfOrderResultDTOS = orderBatchApprovalDTO.getWfOrderResultDTOS();
            HashSet<String> procDefKeys = new HashSet<>();
            HashSet<String> currentNodes = new HashSet<>();
            wfOrderResultDTOS.forEach(wfOrderResultDTO -> {
                procDefKeys.add(wfOrderResultDTO.getProcDefKey());
                currentNodes.add(wfOrderResultDTO.getCurrentNode());
            });
            if (procDefKeys.size() > 1) {
                throw new APIException(APICode.DATA_ERROR, "不在同一流程下无法进行批量审批！");
            } else {
                if (currentNodes.size() > 1) {
                    throw new APIException(APICode.DATA_ERROR, "不在同一节点下无法进行批量审批！");
                }
            }
        } else {
            throw new APIException(APICode.DATA_ERROR, "请选择要审批的工单！");
        }

        List<String> executionIds = wfProcessService.orderBatchApproval(orderBatchApprovalDTO);
        OrderBatchApprovalResponse orderBatchApprovalResponse = new OrderBatchApprovalResponse();
        orderBatchApprovalResponse.setExecutionIds(executionIds);
        return new BaseResult(APICode.SUCCESS.getCode(), "工单批量审批成功！" + TraceIDUtils.getLogTraceId(), orderBatchApprovalResponse);
    }

    /**
     * 更新表单数据
     */
    @ApiOperation(value = "更新表单数据")
    @PostMapping(value = "/updateFormData")
    @ResponseBody
    public BaseResult updateFormData(@RequestBody OrderApprovalDTO orderApprovalDTO) {
        log.info("更新表单数据：processId={},formData={}", orderApprovalDTO.getProcessId(), orderApprovalDTO.getFormData());
        if (StringUtils.isBlank(orderApprovalDTO.getProcessId())) {
            throw new APIException(APICode.DATA_ERROR, "processId不能为空！");
        }
        if (CollectionUtils.isEmpty(orderApprovalDTO.getFormData())) {
            throw new APIException(APICode.DATA_ERROR, "表单数据不能为空！");
        }
        wfFormService.updateFormData(orderApprovalDTO.getProcessId(), orderApprovalDTO.getFormData());
        return new BaseResult<>(APICode.SUCCESS.getCode(), "更新表单信息成功！" + TraceIDUtils.getLogTraceId());
    }

    @ApiOperation(value = "发送验证码")
    @PostMapping(value = "/sendYzm")
    @ResponseBody
    public BaseResult<String> sendYzm(@RequestParam(value = "phone") String phone) {
        log.info("发送验证码:{}", phone);
        String yzm = YzmUtils.generateRandCode(6);
        redisManage.set(phone, yzm);
        //发送短信。。。
        wfEmailLogService.sendSms(phone, yzm);
        return new BaseResult<>(APICode.SUCCESS.getCode(), "发送验证码成功！" + TraceIDUtils.getLogTraceId(), phone);
    }

    @ApiOperation(value = "取消领取任务")
    @PostMapping(value = "/unClaim")
    @ResponseBody
    public BaseResult<String> unClaim(@RequestParam(value = "taskId") String taskId) {
        log.info("取消领取任务:{}", taskId);
        taskService.unclaim(taskId);
        return new BaseResult<>(APICode.SUCCESS.getCode(), "取消领取任务成功！" + TraceIDUtils.getLogTraceId());
    }


}
